#include "Debug.hpp"

#include <iostream>
#include <iomanip>

std::ostream& operator<<(std::ostream &stream, const glm::mat4 & matrix)
{
  const float * p = &matrix[0][0];
  
  stream << std::right << std::setprecision(3) << std::fixed
         << "[ " << std::setw(6) << p[0] << " " << std::setw(6) << p[4] << " " << std::setw(6) << p[8]  << " " << std::setw(6) << p[12] << " ]\n"
         << "[ " << std::setw(6) << p[1] << " " << std::setw(6) << p[5] << " " << std::setw(6) << p[9]  << " " << std::setw(6) << p[13] << " ]\n"
         << "[ " << std::setw(6) << p[2] << " " << std::setw(6) << p[6] << " " << std::setw(6) << p[10] << " " << std::setw(6) << p[14] << " ]\n"
         << "[ " << std::setw(6) << p[3] << " " << std::setw(6) << p[7] << " " << std::setw(6) << p[11] << " " << std::setw(6) << p[15] << " ]\n";
  
  return stream;
}

std::ostream& operator<<(std::ostream &stream, const glm::mat3 & matrix)
{
  const float * p = &matrix[0][0];
  
  stream << std::right << std::setprecision(3) << std::fixed
         << "[ " << std::setw(6) << p[0] << " " << std::setw(6) << p[3] << " " << std::setw(6) << p[6] << " ]\n"
         << "[ " << std::setw(6) << p[1] << " " << std::setw(6) << p[4] << " " << std::setw(6) << p[7] << " ]\n"
         << "[ " << std::setw(6) << p[2] << " " << std::setw(6) << p[5] << " " << std::setw(6) << p[8] << " ]\n";
  return stream;
}

std::ostream& operator<<(std::ostream &stream, const glm::vec4 & vector)
{
  const float * p = &vector[0];
  
  stream << std::right << std::setprecision(3) << std::fixed
         << "[ " << std::setw(6) << p[0] << " " << std::setw(6) << p[1] << " " << std::setw(6) << p[2]  << " " << std::setw(6) << p[3] << " ]\n";
  
  return stream;
}

std::ostream& operator<<(std::ostream &stream, const glm::vec3 & vector)
{
  const float * p = &vector[0];
  
  stream << std::right << std::setprecision(3) << std::fixed
         << "[ " << std::setw(6) << p[0] << " " << std::setw(6) << p[1] << " " << std::setw(6) << p[2]  << " ]\n";
  
  return stream;
}

static const char* getErrorString(GLenum error)
{
  const char * msg = 0;
  switch(error) {
#define Case(Token)  case Token: msg = #Token; break;
    Case(GL_NO_ERROR);
    Case(GL_INVALID_VALUE);
    Case(GL_INVALID_ENUM);
    Case(GL_INVALID_OPERATION);
    Case(GL_STACK_OVERFLOW);
    Case(GL_STACK_UNDERFLOW);
    Case(GL_OUT_OF_MEMORY);
#undef Case        
    default: msg = "(BAD ENUM)";
  }

  return msg;
}


void _checkError(const char * filename, int line)
{
  
  GLenum error;
  const char * errorString;
  
  while ((error = glGetError()) != GL_NO_ERROR) {
    
    errorString = getErrorString(error);
    
    fprintf(stderr, "WARNING %s(%u): glGetError(): %s\n",
                    filename, line, errorString);    
  }
  
  errorString = getErrorString(error);
  fprintf(stderr, "DEBUG %s(%u): glGetError(): %s\n",
                    filename, line, errorString);    
}